LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;

-- Arbiter
-- tableheardarbiter = Whether or not table already heard your request. (So you can move to the next thing.)
-- srcAddressValid = Whether or not the srcAddress being output is valid.
-- desAddressValid = Whether or not the desAddress being output is valid.

ENTITY Arbiter IS
   PORT(
       clock : IN STD_LOGIC;
       outclock : OUT STD_LOGIC;
       asreset : IN STD_LOGIC;
       outasreset : OUT STD_LOGIC;
       outtableheardarbiter : OUT STD_LOGIC;
       tableheardarbiter : IN STD_LOGIC;
       metaportReadySignalOut: OUT STD_LOGIC;
	   srcAddressValid0, srcAddressValid1, srcAddressValid2, srcAddressValid3 : IN STD_LOGIC;
	   OMX_to_ARB_Done : IN STD_LOGIC;
	   outsrcAddressValid0, outsrcAddressValid1, outsrcAddressValid2, outsrcAddressValid3 : OUT STD_LOGIC;
	   desAddressValid0, desAddressValid1, desAddressValid2, desAddressValid3 : IN STD_LOGIC;
	   outdesAddressValid0, outdesAddressValid1, outdesAddressValid2, outdesAddressValid3 : OUT STD_LOGIC;
	   portChoice : OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
	   portReady : OUT STD_LOGIC -- Are any ports ready?;
       );
END Arbiter;




ARCHITECTURE arbiter_arch OF Arbiter IS

COMPONENT TestFF IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC 
	);
END COMPONENT;

-- New Parts! Awesome!

COMPONENT ArbiterChoice00 IS
	PORT
	(
		aset		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (1 DOWNTO 0);
		enable		: IN STD_LOGIC ;
		load		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (1 DOWNTO 0)
	);
END COMPONENT;

COMPONENT ArbiterChoice01 IS
	PORT
	(
		aset		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (1 DOWNTO 0);
		enable		: IN STD_LOGIC ;
		load		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (1 DOWNTO 0)
	);
END COMPONENT;

COMPONENT ArbiterChoice10 IS
	PORT
	(
		aset		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (1 DOWNTO 0);
		enable		: IN STD_LOGIC ;
		load		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (1 DOWNTO 0)
	);
END COMPONENT;

COMPONENT ArbiterChoice11 IS
	PORT
	(
		aset		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR(1 DOWNTO 0);
		enable		: IN STD_LOGIC ;
		load		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR(1 DOWNTO 0)
	);
END COMPONENT;

COMPONENT ArbiterChoiceFF IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC ;
		sclr		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC 
	);
END COMPONENT;

COMPONENT ArbiterLatch IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		data		: IN STD_LOGIC ;
		gate		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC 
	);
END COMPONENT;


	SIGNAL ready : STD_LOGIC_VECTOR (0 to 3);	-- which ports are ready
	SIGNAL thisLast  : STD_LOGIC_VECTOR (1 downto 0) := "11";	-- which port is last?
	SIGNAL newLast : STD_LOGIC_VECTOR (1 downto 0) := "11";	-- which port is last now?
	SIGNAL portReadyInternal : STD_LOGIC;
	SIGNAL tableHeardPort : STD_LOGIC_VECTOR (0 to 3); -- has ready changed? used for shit <- Nice
	
	SIGNAL initialChoice : STD_LOGIC_VECTOR(1 DOWNTO 0) := "00";
	SIGNAL metaChoice0 : STD_LOGIC_VECTOR(1 DOWNTO 0) := "01";
	SIGNAL metaChoice1 : STD_LOGIC_VECTOR(1 DOWNTO 0) := "10";
	SIGNAL metaChoice2 : STD_LOGIC_VECTOR(1 DOWNTO 0) := "11";
	SIGNAL portReadySignal: STD_LOGIC;
	SIGNAL metaportReadySignal: STD_LOGIC;
	SIGNAL choiceready : STD_LOGIC;
	SIGNAL Icanskip : STD_LOGIC;
	

BEGIN
-- Do Stuff

-- Sorry, I gutted this because there's no way in hell you were going to debug that mass of stuff you had before.
  
-- Minimum necessary correct arbiter code (Starves ports, gives preference to higher-numbered ports):
--initialChoice(0) <= ((srcAddressValid2 AND desAddressValid2) OR (srcAddressValid3 AND desAddressValid3));
--initialChoice(1) <= ((srcAddressValid1 AND desAddressValid1) OR (srcAddressValid3 AND desAddressValid2));
--portReady <= ((srcAddressValid0 AND desAddressValid0) OR (srcAddressValid1 AND desAddressValid1) OR (srcAddressValid2 AND desAddressValid2) OR (srcAddressValid3 AND desAddressValid3));

-- Implementation Preventing Starvation!

--HaveIMadeAChoice: ArbiterChoiceFF PORT MAP((asreset), clock , ((portReadySignal)OR(tableheardarbiter)), '0', choiceready);

-- The choice snakes around from 00 to 11 - Stops when a choice is detected.

InitialChoiceRegister: ArbiterChoice00 PORT MAP(asreset, (clock), metaChoice2, (NOT(choiceready) OR tableheardarbiter), '1' , initialChoice);
MetaRegister0: ArbiterChoice01 PORT MAP(asreset, (clock), initialChoice, (NOT(choiceready)  OR tableheardarbiter),'1', metaChoice0);
MetaRegister1: ArbiterChoice10 PORT MAP(asreset, (clock), metaChoice0, (NOT(choiceready)  OR tableheardarbiter), '1', metaChoice1);
MetaRegister2: ArbiterChoice11 PORT MAP(asreset, (clock), metaChoice1, (NOT(choiceready)  OR tableheardarbiter), '1', metaChoice2);
   
-- If the choice I'm at is viable, go with it, and choose the next thing in the queue next time. Has up to a 3 cycle overhead penalty but who cares
portChoice <= initialChoice;

--portReady <= choiceready;--portReadySignal;
portReady <= choiceready AND (OMX_to_ARB_Done OR (NOT(Icanskip)));
metaportReadySignalOut <= metaportReadySignal;

DoLatch: ArbiterLatch PORT MAP (asreset, choiceready, '1', portReadySignal);

--ENTITY ArbiterLatch IS
--	PORT
--	(
--		aclr		: IN STD_LOGIC ;
--		data		: IN STD_LOGIC ;
--		gate		: IN STD_LOGIC ;
--		q		: OUT STD_LOGIC 
--	);
DoSkipFirstTime: ArbiterLatch PORT MAP(asreset, tableheardarbiter, NOT(Icanskip), (Icanskip));

--metaportReadySignal
--portReadySignal
-- '1' used to be OMX_to_ARB_Done
	choiceready <= (NOT(asreset)) AND ( ((NOT(initialChoice(0)) AND NOT(initialChoice(1))) AND (srcAddressValid0 AND desAddressValid0)) 
	OR ((((initialChoice(0)) AND NOT(initialChoice(1))) AND (srcAddressValid1 AND desAddressValid1))) 
	OR (((NOT(initialChoice(0)) AND (initialChoice(1))) AND (srcAddressValid2 AND desAddressValid2))) 
	OR ((((initialChoice(0)) AND (initialChoice(1))) AND (srcAddressValid3 AND desAddressValid3))));

outclock <= clock;
outasreset <= asreset;
outtableheardarbiter <= tableheardarbiter;
outsrcAddressValid0 <= srcAddressValid0;
outsrcAddressValid1 <= srcAddressValid1;
outsrcAddressValid2 <= srcAddressValid2;
outsrcAddressValid3 <= srcAddressValid3;
outdesAddressValid0 <= desAddressValid0;
outdesAddressValid1 <= desAddressValid1;
outdesAddressValid2 <= desAddressValid2;
outdesAddressValid3 <= desAddressValid3;

----portReadySignal <= NOT tableheardarbiter AND(srcAddressValid0 OR srcAddressValid1 OR srcAddressValid2 OR srcAddressValid3);
--
--portChoice(0) <= (tableheardarbiter AND((srcAddressValid2 AND desAddressValid2) OR (srcAddressValid3 AND desAddressValid3)));
--portChoice(1) <= (tableheardarbiter AND((srcAddressValid1 AND desAddressValid1) OR (srcAddressValid3 AND desAddressValid2)));
--Portflip:TestFF PORT MAP(asreset,clock,portReadySignal ,portReady);

END arbiter_arch;